package com.fishingwithme.domain.circle;

import com.fishingwithme.domain.anybiting.CircleMessageClient;
import com.fishingwithme.domain.anybiting.MessageType;
import com.fishingwithme.domain.anybiting.SubType;
import com.fishingwithme.domain.common.Location;
import com.fishingwithme.infrastructure.dtos.anybiting.BaseCircleMessageDto;
import cn.fishingwithme.infrastructure.dtos.circle.*;
import com.fishingwithme.infrastructure.dtos.circle.*;
import com.fishingwithme.infrastructure.mapper.circle.CircleMapper;
import cn.fishingwithme.infrastructure.utils.*;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fishingwithme.infrastructure.utils.*;
import lombok.SneakyThrows;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

import static com.fishingwithme.infrastructure.cfg.RedisConfig.CIRCLE_MESSAGE_CHANNEL;

@Service
public class CircleServiceImpl implements CircleService {
    private static final Logger logger = LoggerFactory.getLogger(CircleServiceImpl.class);
    @Autowired
    private TencentGeocoderClient geocoderClient;
    @Autowired
    private CircleMapper circleMapper;
    @Autowired
    private IdGenerator idGenerator;
    @Autowired
    private ObjectMapperFactory factory;

    @Autowired
    private CircleMessageClient circleMessageClient;

    @Autowired
    private CircleRedisMessagePublisher circleRedisMessagePublisher;

    @Transactional
    @Override
    public Boolean deleteCircle(Long circleId) {
        Boolean isActive = circleMapper.isActive(circleId);
        if (isActive != null && !isActive) {
            int cnt = circleMapper.deleteById(circleId);
            return cnt > 0;
        } else {
            logger.warn("CircleServiceImpl deleteCircle circleId:{} is active", circleId);
            return false;
        }

    }

    @Transactional
    public Boolean active(Long circleId) {
        return this.markActive(circleId, Boolean.TRUE);
    }

    public Boolean inactive(Long circleId) {
        return this.markActive(circleId, Boolean.FALSE);
    }


    public Boolean isActive(Long circleId) {
        Boolean isActive = circleMapper.isActive(circleId);
        return isActive != null && isActive;
    }

    @Override
    public Boolean markActive(Long circleId, Boolean active) {
        Boolean status = circleMapper.markActiveState(circleId, active) > 0;
        //TODO: 报告生成重写
//        if (status && active) {
//            this.sendCircleActiveMessage(circleId);
//        }
        return status;
    }

    @Override
    public List<CircleLocationDto> getCircleLocations(Double latitude, Double longitude, Integer distance) {
        try {
            return circleMapper.getCircleLocations(latitude
                    , longitude, distance).stream().map(CircleLocationDto::formatDtoJson).collect(Collectors.toList());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return List.of();

    }

    @Override
    public void addSpotToCircle(Long circleId, Long spotId) {
        circleMapper.addSpotToCircle(circleId, spotId);
    }

    @Override
    public List<CircleSpotDto> queryCircleSpots(Long circleId, String queryStr) {
        Long userId = CommonUtils.getUserId();
        return circleMapper.queryCircleSpots(circleId, userId, queryStr);
    }

    //TODO: fix it.
    @Override
    public void scheduleCircleMessage() {
//        List<Long> circleIds = circleMapper.getAllActiveCircleIds();
//        for (Long circleId : circleIds) {
//            this.sendCircleActiveMessage(circleId);
//        }
    }


    public void sendCircleActiveMessage(Long circleId) {

        BaseCircleMessageDto circleMessageDto = BaseCircleMessageDto.builder().build();
        //circleMessageDto.setCityCode(circleId);
        circleMessageDto.setBizId(circleId);
        circleMessageDto.setType(MessageType.EVT);
        circleMessageDto.setSubtype(SubType.RPT_N_CIRCLE);
        circleMessageDto.setContent(circleId);
        circleMessageDto.setTimestamp(CommonUtils.now());
        circleMessageDto.setSender("system");
        circleMessageDto.setPriority(0);
        circleRedisMessagePublisher.publish(CIRCLE_MESSAGE_CHANNEL, circleMessageDto);

    }

    @Transactional
    @Override
    public Boolean add(CircleDto circle) {
        try {

            GeocoderResponse reverseResp =
                    CommonUtils.getGeocoder(geocoderClient, new Location(circle.getLatitude(), circle.getLongitude()));
            if (reverseResp.getStatus() == 0) {
                logger.info(Objects.toString(reverseResp));
            } else {
                throw new RuntimeException("获取定位点失败.");
            }
            ObjectMapper mapper = factory.getInstance();
            Circle entity = Circle.builder()
                    .cityCode(reverseResp.getResult().getAdInfo().getCityCode())
                    .city(reverseResp.getResult().getAddressComponent().getCity())
                    .title(circle.getTitle())
                    .latitude(circle.getLatitude())
                    .longitude(circle.getLongitude())
                    .pointsString(mapper.writeValueAsString(circle.getPoints()))
                    .picsString(circle.getPicsString())
                    .description(circle.getDescription())
                    .area(circle.getArea())
                    .build();

            circleMapper.insert(entity);
        } catch (Exception e) {
            logger.error("CircleServiceImpl add circle error", e);
            return false;
        }
        return true;
    }

    @SneakyThrows
    @Override
    public List<CircleDto> getCircles(Location location, Integer distance) {
        return circleMapper.getCirclesByLocation(location.getLatitude(), location.getLongitude(), distance)
                .stream().map(CircleDto::formatDtoJson).collect(Collectors.toList());
    }

    @Override
    public IPage<CircleDto> list(Integer pageNum, Integer pageSize) {
        Page<CircleDto> page = new Page<>(pageNum, pageSize);
        return circleMapper.selectCirclePage(page);
    }

    @Override
    public IPage<CirclePageDto> listPage(Integer pageNum, Integer pageSize) {
        Page<CirclePageDto> page = new Page<>(pageNum, pageSize);
        IPage<CirclePageDto> result = circleMapper.selectCirclePageDto(page);
        // 处理图片字符串到列表的转换
        result.getRecords().forEach(CirclePageDto::formatPics);
        return result;
    }

    @Override
    public CircleDetailDto get(Long id) {
        CircleDetailDto detail = circleMapper.selectCircleDetailById(id);
        if (detail != null) {
            detail.formatPics();
        }
        return detail;
    }

    @Override
    @Transactional
    public Boolean updateCircle(CircleUpdateDto updateDto) {
        if (updateDto.getId() == null) {
            return false;
        }
        return circleMapper.updateCircle(updateDto) > 0;
    }
    
    @Override
    @Transactional
    public Integer batchAddSpotsToCircle(Long circleId, List<Long> spotIds) {
        if (circleId == null || spotIds == null || spotIds.isEmpty()) {
            logger.warn("Invalid parameters for batchAddSpotsToCircle: circleId={}, spotIds={}", circleId, spotIds);
            return 0;
        }
        
        // 验证圈子是否存在
        CircleDetailDto circle = circleMapper.selectCircleDetailById(circleId);
        if (circle == null) {
            logger.warn("Circle not found for circleId: {}", circleId);
            return 0;
        }
        
        int successCount = 0;
        for (Long spotId : spotIds) {
            try {
                int result = circleMapper.addSpotToCircle(circleId, spotId);
                if (result > 0) {
                    successCount++;
                }
            } catch (Exception e) {
                // 忽略重复插入等错误，继续处理其他
                logger.warn("添加spot {} 到圈子 {} 失败，可能已存在: {}", spotId, circleId, e.getMessage());
            }
        }
        
        logger.info("Successfully added {} spots to circle {}", successCount, circleId);
        return successCount;
    }

    @Override
    public IPage<SpotInCircleDto> getCircleSpotsPage(Integer pageNum, Integer pageSize, Long circleId) {
        Page<SpotInCircleDto> page = new Page<>(pageNum, pageSize);
        return circleMapper.selectSpotsByCircleId(page, circleId);
    }

    @Override
    public CityDto getCity(Double latitude, Double longitude) {
        GeocoderResponse reverseResp =
                CommonUtils.getGeocoder(geocoderClient, new Location(latitude,longitude));
        if (reverseResp.getStatus() == 0) {
            logger.info(Objects.toString(reverseResp));
        } else {
            throw new RuntimeException("获取定位点失败.");
        }
        return new CityDto(reverseResp.getResult().getAdInfo().getCityCode(),reverseResp.getResult().getAddressComponent().getCity());
    }
}
